package com.lancoo.ccas53.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lancoo.ccas53.entity.*;
import com.lancoo.ccas53.exception.BizException;
import com.lancoo.ccas53.mapper.*;
import com.lancoo.ccas53.pojo.constant.GlobalConstant;
import com.lancoo.ccas53.pojo.vo.WeekDateVo;
import com.lancoo.ccas53.service.*;
import com.lancoo.ccas53.util.RedisUtil;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 排课计划 服务实现类
 * </p>
 *
 * @author quin.song
 * @since 2024-05-20
 */
@Service
public class TaskInfoServiceImpl extends ServiceImpl<TaskInfoMapper, TaskInfo> implements TaskInfoService {

    @Resource
    private RoomService roomService;
    @Resource
    private TaskProcessService taskProcessService;
    @Resource
    private MajorGradeService majorGradeService;


    @Resource
    private ActiveTeachMapper activeTeachMapper;
    @Resource
    private CampusMapper campusMapper;
    @Resource
    private CollegeMapper collegeMapper;
    @Resource
    private CollegeRoomMapper collegeRoomMapper;
    @Resource
    private CourseMapper courseMapper;
    @Resource
    private CourseApplyMapper courseApplyMapper;
    @Resource
    private CourseWeekMapper courseWeekMapper;
    @Resource
    private CssPreSelectStudentMapper cssPreSelectStudentMapper;
    @Resource
    private CssProhibitStudentMapper cssProhibitStudentMapper;
    @Resource
    private CssRoundCourseMapper cssRoundCourseMapper;
    @Resource
    private CssSelectCourseMapper cssSelectCourseMapper;
    @Resource
    private CssStudentRangeMapper cssStudentRangeMapper;
    @Resource
    private CssTaskInfoMapper cssTaskInfoMapper;
    @Resource
    private CssTaskRoundMapper cssTaskRoundMapper;
    @Resource
    private HolidayMapper holidayMapper;
    @Resource
    private MajorGradeMapper majorGradeMapper;
    @Resource
    private MonitorMapper monitorMapper;
    @Resource
    private MonitorRecordMapper monitorRecordMapper;
    @Resource
    private PeriodSchemeMapper periodSchemeMapper;
    @Resource
    private PlanTeachingMapper planTeachingMapper;
    @Resource
    private PlanTeachingStudentMapper planTeachingStudentMapper;
    @Resource
    private PlanTeachingCourseMapper planTeachingCourseMapper;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private RuleTimeProhibitMapper ruleTimeProhibitMapper;
    @Resource
    private RuleUsableMapper ruleUsableMapper;
    @Resource
    private RuleWeekDayMapper ruleWeekDayMapper;
    @Resource
    private ScheduleMapper scheduleMapper;
    @Resource
    private StudentMapper studentMapper;
    @Resource
    private SubClassMapper subClassMapper;
    @Resource
    private SubClassGroupMapper subClassGroupMapper;
    @Resource
    private TeacherMapper teacherMapper;
    @Resource
    private TeacherCourseMapper teacherCourseMapper;
    @Resource
    private SplitClassService splitClassService;
    @Resource
    private TypeService typeService;
    @Resource
    private TeachingClassService teachingClassService;
    @Resource
    private UserSettingMapper userSettingMapper;
    @Resource
    private StudentRetakeService studentRetakeService;


    @Resource
    private RedisUtil redisUtil;
    @Resource(name = "asyncExecutor")
    private ThreadPoolTaskExecutor executor;

    @Override
    public TaskInfo addTask(TaskInfo taskInfo) {
        //一个学期只能有一个任务
        if (this.lambdaQuery().eq(TaskInfo::getSchoolId, taskInfo.getSchoolId()).eq(TaskInfo::getTerm, taskInfo.getTerm()).exists()) {
            throw new BizException("当前学期已存在");
        }

        this.saveOrUpdate(taskInfo);
        Integer taskId = taskInfo.getTaskId();
        if (taskId > 0) {
            //init 插入流程数据
            taskProcessService.initProcess(taskInfo.getTaskId());
            //同步教室校区
            roomService.syncRoom(taskId, taskInfo.getSchoolId());
            //同步专业 专业年级
            majorGradeService.syncMajorGrade(taskId, taskInfo.getSchoolId());
        }
        return taskInfo;
    }

    @CacheEvict(value = "countWeek", key = "#taskInfo.taskId")
    @Override
    public TaskInfo updateTask(TaskInfo taskInfo) {
        this.updateById(taskInfo);
        return taskInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeTaskByIds(List<Integer> taskIds) {
        this.removeByIds(taskIds);
        //删除redis中的数据
        redisUtil.del(GlobalConstant.REDIS_ROUND_KEY);
        executor.submit(() -> {
            try {
                activeTeachMapper.delete(new LambdaQueryWrapper<ActiveTeach>().in(ActiveTeach::getTaskId, taskIds));
                campusMapper.delete(new LambdaQueryWrapper<Campus>().in(Campus::getTaskId, taskIds));
                collegeMapper.delete(new LambdaQueryWrapper<College>().in(College::getTaskId, taskIds));
                collegeRoomMapper.delete(new LambdaQueryWrapper<CollegeRoom>().in(CollegeRoom::getTaskId, taskIds));
                //课程表数据
                courseMapper.delete(new LambdaQueryWrapper<Course>().in(Course::getTaskId, taskIds));
                courseApplyMapper.delete(new LambdaQueryWrapper<CourseApply>().in(CourseApply::getTaskId, taskIds));
                courseWeekMapper.delete(new LambdaQueryWrapper<CourseWeek>().in(CourseWeek::getTaskId, taskIds));

                //选课数据
                cssPreSelectStudentMapper.delete(new LambdaQueryWrapper<CssPreSelectStudent>().in(CssPreSelectStudent::getTaskId, taskIds));
                cssProhibitStudentMapper.delete(new LambdaQueryWrapper<CssProhibitStudent>().in(CssProhibitStudent::getTaskId, taskIds));
                cssRoundCourseMapper.delete(new LambdaQueryWrapper<CssRoundCourse>().in(CssRoundCourse::getTaskId, taskIds));
                cssSelectCourseMapper.delete(new LambdaQueryWrapper<CssSelectCourse>().in(CssSelectCourse::getTaskId, taskIds));
                cssStudentRangeMapper.delete(new LambdaQueryWrapper<CssStudentRange>().in(CssStudentRange::getTaskId, taskIds));
                cssTaskInfoMapper.delete(new LambdaQueryWrapper<CssTaskInfo>().in(CssTaskInfo::getTaskId, taskIds));
                cssTaskRoundMapper.delete(new LambdaQueryWrapper<CssTaskRound>().in(CssTaskRound::getTaskId, taskIds));

                //节假日
                holidayMapper.delete(new LambdaQueryWrapper<Holiday>().in(Holiday::getTaskId, taskIds));
                //年级专业
                majorGradeMapper.delete(new LambdaQueryWrapper<MajorGrade>().in(MajorGrade::getTaskId, taskIds));

                monitorMapper.delete(new LambdaQueryWrapper<Monitor>().in(Monitor::getTaskId, taskIds));
                monitorRecordMapper.delete(new LambdaQueryWrapper<MonitorRecord>().in(MonitorRecord::getTaskId, taskIds));

                periodSchemeMapper.delete(new LambdaQueryWrapper<PeriodScheme>().in(PeriodScheme::getTaskId, taskIds));
                planTeachingMapper.delete(new LambdaQueryWrapper<PlanTeaching>().in(PlanTeaching::getTaskId, taskIds));
                planTeachingStudentMapper.delete(new LambdaQueryWrapper<PlanTeachingStudent>().in(PlanTeachingStudent::getTaskId, taskIds));
                planTeachingCourseMapper.delete(new LambdaQueryWrapper<PlanTeachingCourse>().in(PlanTeachingCourse::getTaskId, taskIds));
                roomMapper.delete(new LambdaQueryWrapper<Room>().in(Room::getTaskId, taskIds));
                ruleTimeProhibitMapper.delete(new LambdaQueryWrapper<RuleTimeProhibit>().in(RuleTimeProhibit::getTaskId, taskIds));
                ruleUsableMapper.delete(new LambdaQueryWrapper<RuleUsable>().in(RuleUsable::getTaskId, taskIds));
                ruleWeekDayMapper.delete(new LambdaQueryWrapper<RuleWeekDay>().in(RuleWeekDay::getTaskId, taskIds));
                scheduleMapper.delete(new LambdaQueryWrapper<Schedule>().in(Schedule::getTaskId, taskIds));
                studentMapper.delete(new LambdaQueryWrapper<Student>().in(Student::getTaskId, taskIds));
                studentRetakeService.lambdaUpdate().in(StudentRetake::getTaskId, taskIds).remove();
                subClassMapper.delete(new LambdaQueryWrapper<SubClass>().in(SubClass::getTaskId, taskIds));
                subClassGroupMapper.delete(new LambdaQueryWrapper<SubClassGroup>().in(SubClassGroup::getTaskId, taskIds));
                teacherMapper.delete(new LambdaQueryWrapper<Teacher>().in(Teacher::getTaskId, taskIds));
                teacherCourseMapper.delete(new LambdaQueryWrapper<TeacherCourse>().in(TeacherCourse::getTaskId, taskIds));
                typeService.lambdaUpdate().in(Type::getTaskId, taskIds).remove();
                taskProcessService.lambdaUpdate().in(TaskProcess::getTaskId, taskIds).remove();
                //删除教学班
                List<Long> teachingClassIds = teachingClassService.lambdaQuery().in(TeachingClass::getTaskId, taskIds).select(TeachingClass::getTeachingClassId).list()
                        .stream().map(TeachingClass::getTeachingClassId).collect(Collectors.toList());
                teachingClassService.deleteClass(teachingClassIds);
                splitClassService.lambdaUpdate().in(SplitClass::getTaskId, taskIds).remove();

                userSettingMapper.delete(new LambdaQueryWrapper<UserSetting>().in(UserSetting::getTaskId, taskIds));
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    @Override
    @Cacheable(cacheNames = "countWeek", key = "#taskId")
    public WeekDateVo countWeek(Integer taskId) {
        WeekDateVo weekDateVo = new WeekDateVo();
        List<WeekDateVo.WeekDate> weekDates = new ArrayList<>();

        TaskInfo taskInfo = this.getById(taskId);
        LocalDateTime termBeginTime = taskInfo.getTermBeginTime();
        LocalDateTime termEndTime = taskInfo.getTermEndTime();
        Integer cycleDays = taskInfo.getCycleDay();

        LocalDateTime currentStartDate = termBeginTime;
        LocalDateTime currentEndDate;
        int i = 1;
        while (!currentStartDate.isAfter(termEndTime)) {
            if (cycleDays % 7 == 0 && weekDates.isEmpty()) {
                // Cycle days is a multiple of 7, align with real week for the first week
                currentEndDate = currentStartDate.with(DayOfWeek.SUNDAY);
                if (cycleDays == 14) {
                    currentEndDate = currentEndDate.plusDays(1);
                    currentEndDate = currentEndDate.with(DayOfWeek.SUNDAY);
                }
            } else if (cycleDays % 7 == 0) {
                // Cycle days is a multiple of 7, align with real week
                currentStartDate = currentStartDate.with(DayOfWeek.MONDAY);
                currentEndDate = currentStartDate.plusDays(cycleDays - 1);
            } else {
                // Cycle days is not a multiple of 7, use the given start date as "Monday"
                currentEndDate = currentStartDate.plusDays(cycleDays - 1);
            }

            if (currentEndDate.isAfter(termEndTime)) {
                currentEndDate = termEndTime;
            }

            weekDates.add(new WeekDateVo.WeekDate().setWeek(i).setStart(currentStartDate).setEnd(currentEndDate));
            currentStartDate = currentEndDate.plusDays(1);
            i++;
        }
        weekDateVo.setWeekCount(i - 1);
        weekDateVo.setWeekDates(weekDates);
        return weekDateVo;
    }


}


